package studystat;

import java.util.ArrayList;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;

/**
 * AchievementEngine beheert alle achievements die gebruikers kunnen verdienen
 *
 */

public class AchievementManager {
	
	private ArrayList<Achievement> achievements;
	
	private DatastoreService datastore;
	
	private static AchievementManager instance = null;
	
	private AchievementManager() {	
		
		achievements = new ArrayList<Achievement>();
		datastore = DatastoreServiceFactory.getDatastoreService();
		// zet MogelijkeAchievements in de datastore
		int i = 0;
		Query q = new Query("MogelijkeAchievement");
		q.addFilter("Naam", Query.FilterOperator.NOT_EQUAL, null);
		PreparedQuery pq = datastore.prepare(q);
		for (Entity result : pq.asIterable()) {
			i++;
		}
		System.out.println("Aantal achievements in datastore:"+i);
		if(i==0){
			setAchievements();
		}
		else{
			setAchievementslijst();
		}
		System.out.println("Aantal achievements na initialisatie:"+achievements.size());
		setBehaaldeAchievementsVanStudenten();
		
		// mogelijke achievements uit datastore halen en in lijst zetten
		Query q1 = new Query("MogelijkeAchievement");
		q1.addFilter("Naam", Query.FilterOperator.NOT_EQUAL, null);
		PreparedQuery pq1 = datastore.prepare(q1);
		for (Entity result1 : pq1.asIterable()) {
			Achievement achievement = new Achievement((String) result1.getProperty("Naam"));
			achievement.setNaam((String) result1.getProperty("Naam"));
			achievement.setTitel((String) result1.getProperty("Titel"));
			List<Conditie> condities = new ArrayList<Conditie>();
			UrenConditie conditie = new UrenConditie((String) result1.getProperty("Naam"), (Long) result1.getProperty("InHoeveelTijd"), (Long) result1.getProperty("UrenNodig"));
			condities.add(conditie);
			achievement.setCondities(condities);
			
		}
	}

	public static AchievementManager getInstance() {
		if( instance == null ) {
			instance = new AchievementManager();
		}
		return instance;
	}
	
	/**
	 * Geeft een lijst met alle achievements die verdiend zijn,
	 * afgaande op de lijst met activiteiten
	 * @param activiteiten	Een lijst met activiteiten
	 * @return	Een lijst met achievements die verdiend zijn
	 */
	
	public List<Achievement> sync(List<Activiteit> activiteiten) {
		List<Achievement> verdiend = new ArrayList<Achievement>();
		for(Achievement achievement : achievements) {
			if(achievement.isVoldaan(activiteiten)) {
				verdiend.add(achievement);
			}
		}
		return verdiend;
	}
	
	public void setAchievementslijst(){
		Query q = new Query("MogelijkeAchievement");
		q.addFilter("Naam", Query.FilterOperator.NOT_EQUAL, null);
		PreparedQuery pq = datastore.prepare(q);
		System.out.println("Aantal achievements gevonden: "+pq.countEntities(FetchOptions.Builder.withDefaults()));
		for (Entity result : pq.asIterable()) {
			Achievement achievement = new Achievement((String) result.getProperty("Naam"));
			achievement.setTitel((String) result.getProperty("Titel"));
			List<Conditie> condities = new ArrayList<Conditie>();
			long duurConditie = (Long) result.getProperty("InHoeveelTijd");
			long duurActi = (Long) result.getProperty("UrenNodig");
			UrenConditie conditie = new UrenConditie((String) result.getProperty("Naam"), duurConditie, duurActi);
			condities.add(conditie);
			achievement.setCondities(condities);
			achievements.add(achievement);
		}
	}
	
	//TODO methode werkt niet!!
	public void setBehaaldeAchievementsVanStudenten(){
		Query q = new Query("BehaaldeAchievement");
		q.addFilter("Student", Query.FilterOperator.NOT_EQUAL, null);
		PreparedQuery pq = datastore.prepare(q);
		System.out.println("Aantal behaaldeachievements totaal: "+pq.countEntities(FetchOptions.Builder.withDefaults()));
		for (Entity result : pq.asIterable()) {
			Achievement achievement = new Achievement((String) result.getProperty("Naam"));
			achievement.setTitel((String) result.getProperty("Titel"));
			List<Conditie> condities = new ArrayList<Conditie>();
			long duurConditie = (Long) result.getProperty("InHoeveelTijd");
			long duurActi = (Long) result.getProperty("UrenNodig");
			UrenConditie conditie = new UrenConditie((String) result.getProperty("Naam"), duurConditie, duurActi);
			condities.add(conditie);
			achievement.setCondities(condities);
			StudentManager.getInstance().getStudent((String) result.getProperty("Student")).addAchievement(achievement);
		}	
	}
	
	public void setAchievements(){
		//TODO Test of werkt!!!!! (voor DemoDag!)
		Achievement eerste = new Achievement("1 minuut gestudeerd voor alle vakken samen");
			List<Conditie> condities30sec = new ArrayList<Conditie>();
			UrenConditie conditie30sec = new UrenConditie("1 minuut gestudeerd voor alle vakken samen",60*24*7*(13+3+3+1),1); //13 weken les, 3 weken blok, 3 weken examens, 1 week vakantie 
			condities30sec.add(conditie30sec);
			eerste.setCondities(condities30sec);
			eerste.setTitel("Starter");
			achievements.add(eerste);
		Achievement tienprocent = new Achievement("90 uur gestudeerd voor alle vakken samen");
			List<Conditie> condities10 = new ArrayList<Conditie>();
			UrenConditie conditietien = new UrenConditie("90 uren gestudeerd voor alle vakken samen",60*24*7*(13+3+3+1),60*90); //13 weken les, 3 weken blok, 3 weken examens, 1 week vakantie 
			condities10.add(conditietien);
			tienprocent.setCondities(condities10);
			tienprocent.setTitel("Beginner");
			achievements.add(tienprocent);
		Achievement twintigprocent = new Achievement("180 uur gestudeerd voor alle vakken samen");
			UrenConditie conditietwintig = new UrenConditie("180 uren gestudeerd voor alle vakken samen",60*24*7*(13+3+3+1),60*180); //13 weken les, 3 weken blok, 3 weken examens, 1 week vakantie 
			List<Conditie> condities20 = new ArrayList<Conditie>();
			condities20.add(conditietwintig);
			twintigprocent.setCondities(condities20);
			twintigprocent.setTitel("Gevorderde");
			achievements.add(twintigprocent);
		Achievement vijftigprocent = new Achievement("450 uur gestudeerd voor alle vakken samen");
			UrenConditie conditievijftig = new UrenConditie("450 uren gestudeerd voor alle vakken samen",60*24*7*(13+3+3+1),60*450); //13 weken les, 3 weken blok, 3 weken examens, 1 week vakantie 
			List<Conditie> condities50 = new ArrayList<Conditie>();
			condities50.add(conditievijftig);
			vijftigprocent.setCondities(condities50);
			vijftigprocent.setTitel("Expert");
			achievements.add(vijftigprocent);
		Achievement honderdprocent = new Achievement("900 uur gestudeerd voor alle vakken samen");
			UrenConditie conditiehonderd = new UrenConditie("900 uren gestudeerd voor alle vakken samen",60*24*7*(13+3+3+1),60*900); //13 weken les, 3 weken blok, 3 weken examens, 1 week vakantie 
			List<Conditie> condities100 = new ArrayList<Conditie>();
			condities100.add(conditiehonderd);
			honderdprocent.setCondities(condities100);
			honderdprocent.setTitel("Heer en Meester over de Materie");
			achievements.add(honderdprocent);
		System.out.println("Grootte achievements in setAchievements(): "+achievements.size());
		for(int i = 0; i<achievements.size(); i++){
			Entity achievement = new Entity("MogelijkeAchievement");
			achievement.setProperty("Naam", achievements.get(i).getNaam());
			achievement.setProperty("Titel",achievements.get(i).getTitel());
			achievement.setProperty("UrenNodig",((UrenConditie)achievements.get(i).getCondities().get(0)).getDuurActi());
			achievement.setProperty("InHoeveelTijd",((UrenConditie)achievements.get(i).getCondities().get(0)).getDuurConditie());
			datastore.put(achievement);
			
		}
	}
	
	// Retourneert een lijst met nieuw behaalde achievements
	public List<Achievement> controleerAchievements(String googleAccount){
		int totaleStudieTijd = Statistiek.getInstance().berekenTotaleStudietijd(StudentManager.getInstance().getStudent(googleAccount));
		System.out.println("Totale studietijd in min: "+totaleStudieTijd);
		Achievement achievement = null;
		List<Achievement> behaalde = new ArrayList<Achievement>();
		List<Achievement> netBehaalde = new ArrayList<Achievement>();
		System.out.println("Grootte achievements (mogelijk): "+achievements.size());
		for( int i = 0; i<achievements.size(); i++){
			achievement = achievements.get(i);
			Conditie conditie = null;
			boolean check = true;
			for(int j =0; j<achievement.getCondities().size() && check ;j++){
				conditie =  achievements.get(i).getCondities().get(j);
				System.out.println("Conditie: "+conditie);
					if(conditie instanceof studystat.UrenConditie){
						UrenConditie test = (UrenConditie)achievements.get(i).getCondities().get(j);
						if(!test.isVoldaan(totaleStudieTijd)){
							check = false;
						}
				}
			}
			System.out.println("Check: "+check);
			System.out.println("Achievement: "+achievement);
			if(check){
				behaalde.add(achievement);
			}
			System.out.println("Grootte behaalde (alle behaalde achievements): "+behaalde.size());
		}
		System.out.println("Grootte al behaalde achievements van student: "+StudentManager.getInstance().getStudent(googleAccount).getAchievements().size());
		if(behaalde.size() > StudentManager.getInstance().getStudent(googleAccount).getAchievements().size()){
			for(int i = 0; i< behaalde.size() ; i++){
				boolean nieuw = true;
				for(int j = 0; j< StudentManager.getInstance().getStudent(googleAccount).getAchievements().size(); j++){
					if(behaalde.get(i).equals(StudentManager.getInstance().getStudent(googleAccount).getAchievements().get(j))){
						nieuw = false;
					}
				}
					if(nieuw){
						netBehaalde.add(behaalde.get(i));
					}
				}
		}
		System.out.println("grootte netBehaalde: "+netBehaalde.size());
		return netBehaalde;
	}
	
	public List<Achievement> saveNieuweAchievements(String googleAccount){
		int totaleStudieTijd = Statistiek.getInstance().berekenTotaleStudietijd(StudentManager.getInstance().getStudent(googleAccount));
		System.out.println("Totale studietijd in min: "+totaleStudieTijd);
		Achievement achievement = null;
		List<Achievement> behaalde = new ArrayList<Achievement>();
		List<Achievement> netBehaalde = new ArrayList<Achievement>();
		System.out.println("Grootte achievements (mogelijk): "+achievements.size());
		for( int i = 0; i<achievements.size(); i++){
			achievement = achievements.get(i);
			Conditie conditie = null;
			boolean check = true;
			for(int j =0; j<achievement.getCondities().size() && check ;j++){
				conditie =  achievements.get(i).getCondities().get(j);
				System.out.println("Conditie: "+conditie);
					if(conditie instanceof studystat.UrenConditie){
						UrenConditie test = (UrenConditie)achievements.get(i).getCondities().get(j);
						if(!test.isVoldaan(totaleStudieTijd)){
							check = false;
						}
				}
			}
			System.out.println("Check: "+check);
			System.out.println("Achievement: "+achievement);
			if(check){
				behaalde.add(achievement);
			}
			System.out.println("Grootte behaalde (alle behaalde achievements): "+behaalde.size());
		}
		System.out.println("Grootte al behaalde achievements van student: "+StudentManager.getInstance().getStudent(googleAccount).getAchievements().size());
		if(behaalde.size() > StudentManager.getInstance().getStudent(googleAccount).getAchievements().size()){
			for(int i = 0; i< behaalde.size() ; i++){
				boolean nieuw = true;
				for(int j = 0; j< StudentManager.getInstance().getStudent(googleAccount).getAchievements().size(); j++){
					if(behaalde.get(i).equals(StudentManager.getInstance().getStudent(googleAccount).getAchievements().get(j))){
						nieuw = false;
					}
				}
					if(nieuw){
						netBehaalde.add(behaalde.get(i));
					}
				}
		}
		System.out.println("grootte netBehaalde: "+netBehaalde.size());
		StudentManager.getInstance().getStudent(googleAccount).setAchievements(behaalde);
		for(int i = 0; i<netBehaalde.size(); i++){
			Entity behaaldeAchievement = new Entity ("BehaaldeAchievement");
			behaaldeAchievement.setProperty("Naam", netBehaalde.get(i).getNaam());
			behaaldeAchievement.setProperty("Titel",netBehaalde.get(i).getTitel());
			behaaldeAchievement.setProperty("UrenNodig",((UrenConditie)netBehaalde.get(i).getCondities().get(0)).getDuurActi());
			behaaldeAchievement.setProperty("InHoeveelTijd",((UrenConditie)netBehaalde.get(i).getCondities().get(0)).getDuurConditie());
			behaaldeAchievement.setProperty("Student", googleAccount);
			datastore.put(behaaldeAchievement);
		}
		return netBehaalde;
	}
	
	public List<Achievement> getMogelijkeAchievements(){
		return achievements;
	}
	
}
